import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# 设置中文显示
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
plt.rcParams["axes.unicode_minus"] = False  # 设置中文后，部分可能为乱码方块，解决负号显示问题
file_path = r"C:\Users\byf37\Desktop\albums (1).csv"  # r前缀处理Windows路径中的反斜杠
try:
    df = pd.read_csv(file_path)
    print("数据加载成功，共有", df.shape[0], "条记录，", df.shape[1], "个字段")#分别是读取行数和列数
except FileNotFoundError:
    print(f"错误：未找到文件 {file_path}，请检查路径是否正确")
    exit()
except Exception as e:
    print(f"加载数据时出错：{str(e)}")
    exit()
# 数据预处理
print("\n数据预处理中...")
# dropna删除包含缺失值的行，subset选择特定的参数
df = df.dropna(subset=["genre", "year_of_pub", "num_of_sales",
                       "rolling_stone_critic", "mtv_critic", "music_maniac_critic"])
# 确保年份为整数
df["year_of_pub"] = df["year_of_pub"].astype(int)
# 确保销量和单曲数量为非负数值
df = df[(df["num_of_sales"] >= 0) & (df["num_of_tracks"] >= 0)]
#————————————————————————————————————————————————————————————————
# 1. 统计各类型专辑的数量
print("\n分析1：各类型专辑的数量统计")
genre_count = df["genre"].value_counts()#pandas的value_counts()排序，默认降序
print("所有专辑类型数量：")
print(genre_count)
# 计算中位数作为分割点
median_count = genre_count.median()
high_volume = genre_count[genre_count >= median_count]
low_volume = genre_count[genre_count < median_count]
# 创建两个子图
fig, axes = plt.subplots(2, 1, figsize=(15, 12))
# 绘制数量较多的类型柱状图
sns.barplot(x=high_volume.index, y=high_volume.values, palette="Set2", ax=axes[0])
palette=["red", "blue", "green"]
axes[0].set_title(f"专辑数量较多的类型（≥{int(median_count)}张）", fontsize=14)
axes[0].set_xlabel("")
axes[0].set_ylabel("专辑数量")
axes[0].tick_params(axis='x', rotation=45, labelsize=9)
# 为每个柱子添加数值标签
for i, v in enumerate(high_volume.values):
    axes[0].text(i, v + 50, str(v), ha='center', fontsize=8)

# 绘制数量较少的类型柱状图
sns.barplot(x=low_volume.index, y=low_volume.values, palette="Set2", ax=axes[1])
palette=["orange","yellow","pink"]
axes[1].set_title(f"专辑数量较少的类型（<{int(median_count)}张）", fontsize=14)
axes[1].set_xlabel("专辑类型")
axes[1].set_ylabel("专辑数量")
axes[1].tick_params(axis='x', rotation=45, labelsize=9)
# 为每个柱子添加数值标签
for i, v in enumerate(low_volume.values):
    axes[1].text(i, v + 5, str(v), ha='center', fontsize=7)
plt.tight_layout()
plt.savefig("1_专辑类型数量分布_全量双柱状图.png")
plt.show()
#——————————————————————————————————————————————————————————
# 2. 统计各类型专辑的销量总数
print("\n分析2：各类型专辑的销量总数统计")
genre_sales = df.groupby("genre")["num_of_sales"].sum().sort_values(ascending=False)
print("所有专辑类型总销量：")
print(genre_sales)
# 计算销量中位数作为分割点
median_sales = genre_sales.median()
high_sales = genre_sales[genre_sales >= median_sales]
low_sales = genre_sales[genre_sales < median_sales]
# 创建两个子图
fig, axes = plt.subplots(2, 1, figsize=(15, 12))

# 绘制销量较高的类型柱状图
sns.barplot(x=high_sales.index, y=high_sales.values, palette="cool", ax=axes[0])
axes[0].set_title(f"销量较高的专辑类型（≥{int(median_sales)}张）", fontsize=14)
axes[0].set_xlabel("")
axes[0].set_ylabel("总销量（张）")
axes[0].tick_params(axis='x', rotation=45, labelsize=9)

# 为每个柱子添加数值标签
for i, v in enumerate(high_sales.values):
    axes[0].text(i, v + 100000, f"{v:,}", ha='center', bbox=dict(facecolor='white', alpha=0.8), fontsize=8)

# 绘制销量较低的类型柱状图
sns.barplot(x=low_sales.index, y=low_sales.values, palette="Greens_d", ax=axes[1])
axes[1].set_title(f"销量较低的专辑类型（<{int(median_sales)}张）", fontsize=14)
axes[1].set_xlabel("专辑类型")
axes[1].set_ylabel("总销量（张）")
axes[1].tick_params(axis='x', rotation=45, labelsize=9)
# 为每个柱子添加数值标签
for i, v in enumerate(low_sales.values):
    axes[1].text(i, v + 5000, f"{v:,}", ha='center', bbox=dict(facecolor='white', alpha=0.8), fontsize=7)
plt.tight_layout()
plt.savefig("2_专辑类型总销量_全量双柱状图.png")
plt.show()
# 3. 统计近20年每年发行的专辑数量和单曲数量
print("\n分析3：近20年每年发行的专辑数量和单曲数量")
current_year = 2018
start_year = current_year - 13
recent_years = df[(df["year_of_pub"] >= start_year) & (df["year_of_pub"] <= current_year)]
# 按年份统计
yearly_data = recent_years.groupby("year_of_pub").agg(
    专辑数量=("album_title", "count"),
    单曲总数=("num_of_tracks", "sum")
).reset_index()
print(f"近20年（{start_year}-{current_year}）统计结果：")
print(yearly_data)
# 可视化
fig, ax1 = plt.subplots(figsize=(14, 7))
# 专辑数量
ax1.plot(yearly_data["year_of_pub"],yearly_data["专辑数量"],color="blue",marker="o",label="专辑数量")
ax1.set_xlabel("年份")
ax1.set_ylabel("专辑数量", color="blue")
ax1.tick_params(axis="y", labelcolor="blue")
# 单曲总数
ax2 = ax1.twinx()
ax2.plot(yearly_data["year_of_pub"], yearly_data["单曲总数"], color="green", marker="s", label="单曲总数")
ax2.set_ylabel("单曲总数", color="green")
ax2.tick_params(axis="y", labelcolor="green")
plt.title(f"近20年（{start_year}-{current_year}）专辑数量与单曲总数趋势", fontsize=20)
fig.tight_layout()
plt.savefig("3_近20年专辑与单曲趋势.png")
plt.show()

# 4. 分析总销量前五的专辑类型的各年份销量
print("\n分析4：总销量前五的专辑类型的各年份销量")
top5_genres = genre_sales.index[:5].tolist()
# 筛选数据并按年份和类型统计销量
top5_data = recent_years[recent_years["genre"].isin(top5_genres)]
yearly_top5_sales = top5_data.groupby(["year_of_pub", "genre"])["num_of_sales"].sum().unstack()
print("总销量前五的专辑类型：",top5_genres)
print("总销量前五的专辑销量：",
      yearly_top5_sales)
plt.figure(figsize=(14, 8))
yearly_top5_sales.plot(kind="line", marker="o", linewidth=2, figsize=(14, 8))
plt.title(f"近20年总销量前五类型的年度销量趋势", fontsize=15)
plt.xlabel("年份")
plt.ylabel("年度销量（张）")
plt.legend(title="专辑类型", bbox_to_anchor=(1.05, 1), loc='upper left')  # 图例放在右侧
plt.grid(linestyle="--", alpha=0.7)
plt.tight_layout()
plt.savefig("4_前五类型年度销量趋势.png")
plt.show()

# 5. 分析总销量前五的专辑类型在不同评分体系中的平均评分
print("\n分析5：总销量前五的专辑类型在不同评分体系中的平均评分")
top5_ratings = df[df["genre"].isin(top5_genres)].groupby("genre").agg(
    滚石评分=("rolling_stone_critic", "mean"),
    MTV评分=("mtv_critic", "mean"),
    音乐达人评分=("music_maniac_critic", "mean")
).reset_index()
print("各类型平均评分：")
print(top5_ratings.round(2))
# 绘制柱状图
df = pd.DataFrame(top5_ratings)
x = np.arange(len(df['genre']))
width = 0.25
multiplier = 0
fig, ax = plt.subplots(layout='constrained')
for attribute, measurement in df.items():
    if attribute == 'genre':
        continue
    offset = width * multiplier
    rects = ax.bar(x + offset, measurement, width, label=attribute)
    ax.bar_label(rects, padding=3, fmt='%.2f')
    multiplier += 1
ax.set_ylabel('平均评分')
ax.set_title('不同专辑类型在各评分体系中的平均评分')
ax.set_xticks(x + width, df['genre'])
ax.legend(loc='upper left',bbox_to_anchor=(1, 1))
ax.set_ylim(2.65, 2.9)
plt.savefig("5_总销量前五的专辑平均评分.png")
plt.show()
print("\n所有分析完成,图表已保存至当前运行目录")
